<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <button onclick="playAudio()">playAudio</button>
  <button onclick="resumeAudio()">resumeAudio</button>
  <button onclick="stopAudio()">stopAudio</button>

  <button onclick="controlDistortion()">失真</button>
  <button onclick="controlConvolver()">混音</button>
  <script>
    var ctx = new (window.AudioContext || window.webkitAudioContext());
    let source = ctx.createBufferSource();
    let gainNode = ctx.createGain();
    let biquadFilter = ctx.createBiquadFilter(); // 创建双二阶滤波器，返回 WaveShaperNode.常用于添加失真效果
    let distortion = ctx.createWaveShaper(); // 创建双二阶滤波器，返回 WaveShaperNode.常用于添加失真效果
    let convolver = ctx.createConvolver(); // 创建一个ConvolverNode，通常用来对你的音频应用混响效果

    async function playAudio() {
      const audioBuffer = await loadAudio();
      playSound(audioBuffer);
    }
    async function resumeAudio() {
      if (ctx.state === 'running') {
        ctx.suspend();
      } else if (ctx.state === 'suspended') {
        ctx.resume();
      }
    }
    async function stopAudio() {
      source.stop();
    }
    async function loadAudio() {
      const audioUrl = 'love105.mp3';
      const res = await fetch(audioUrl);
      const arrayBuffer = await res.arrayBuffer();// byte array字节数组
      const audioBuffer = await ctx.decodeAudioData(arrayBuffer, function (decodeData) { return decodeData });
      return audioBuffer;
    }
    async function playSound(audioBuffer) {
      var myArrayBuffer = getDefineBuffer(); // 数据源使用刚生成的白噪音
      source.buffer = myArrayBuffer;
      convolver.buffer = myArrayBuffer;
      source.loop = true; //循环播放

      source.connect(distortion);
      distortion.connect(biquadFilter);
      biquadFilter.connect(gainNode);

      convolver.connect(gainNode);

      gainNode.connect(ctx.destination);
      source.start(0); //立即播放
    }

    function getDefineBuffer() {
      var channels = 2;
      var frameCount = ctx.sampleRate * 5.0;
      var myArrayBuffer = ctx.createBuffer(channels, frameCount, ctx.sampleRate);
      for (var channel = 0; channel < channels; channel++) {
        var nowBuffering = myArrayBuffer.getChannelData(channel);
        for (var i = 0; i < frameCount; i++) {
          nowBuffering[i] = Math.random() * 2 - 1;
        }
      }
      return myArrayBuffer;
    }

    let controlDistortion = function (value) {
      distortion.curve = makeDistortionCurve(400);
    };
    // 失真  https://stackoverflow.com/questions/22312841/waveshaper-node-in-webaudio-how-to-emulate-distortion
    function makeDistortionCurve(amount) {
      var k = typeof amount === "number" ? amount : 50,
        n_samples = 44100,
        curve = new Float32Array(n_samples),
        deg = Math.PI / 180,
        i = 0,
        x;
      for (; i < n_samples; ++i) {
        x = (i * 2) / n_samples - 1;
        curve[i] = ((3 + k) * x * 20 * deg) / (Math.PI + k * Math.abs(x));
      }
      return curve;
    }

    // controlGainNode();
    function controlGainNode() {
      var max = window.innerHeight;
      document.addEventListener("mousemove", function (event) {
        var y = event.clientY;//取得纵坐标
        var volume = (y / max).toFixed(2);
        gainNode.gain.value = volume
      })
    }

    // 添加混响
    let controlConvolver = function (value) {
      biquadFilter.disconnect(0);
      biquadFilter.connect(convolver)
    }
  </script>

</body>

</html>